<?php
/**
 * Zend_Netflix Class.
 *
 * @author Armando Padilla, armando_padilla_81@yahoo.com
 * @package Zend_Service_Netflix
 * 
 */ 
require_once "Exception.php";

class Zend_Service_Netflix {  
  
    /**
     * Netflix API URI
     */  
    const URI_BASE = "http://api.netflix.com";  
      
    /**
     * NETFLIX API-USER URI
     */  
    const API_USER_URI_BASE = "https://api-user.netflix.com";  
      
    /**
     * OAuth Signiture Method.
     * HMAC-SHA1 OR PLAINTEXT
     */  
    const SIGNITURE_METHOD = 'PLAINTEXT';  
      
    /**
     * OAuth Version
     */  
    const VERSION = '1.0';  
      
    /**
     * Shared Secret.
     *
     * @var unknown_type
     */  
    protected $_sharedSecret = '';  
      
    /**
     * Consumer Key. (Application Id)
     *
     * @var unknown_type
     */  
    protected $_consumerKey = '';  
  
    /**
     * Rest Object. Used for REST calls.
     *
     * @var unknown_type
     */  
    protected $_restClient = null;  
      
    /**
     * Generated Application Name returned by Netflix
     *
     * @var unknown_type
     */  
    protected $_applicationName = '';  
      
      
    /**
     * Generated Request Token Secret by Netflix.
     *
     * @var unknown_type
     */  
    public $_requestTokenSecret = '';  
      
    /**
     * Generated Request Token from Netflix.
     *
     * @var unknown_type
     */  
    public $_requestToken = '';  
      
      
    /**
     * Access Token Required to Access User data.
     *
     * @var unknown_type
     */  
    public $accessToken = '';  
      
    /**
     * Access Token Secret Required To Access User data.
     *
     * @var unknown_type
     */  
    public $accessTokenSecret = '';  
      
      
	/**
	 * Constructor
	 *
	 * @param String $applicationId
	 * @param String $sharedSecret
	 * @param String $accessToken
	 * @param String $accessTokenSecret
	 */  
    public function __construct($applicationId, $sharedSecret, $accessToken='', $accessTokenSecret=''){
    
    	if(!empty($applicationId)){
			$this->_consumerKey   = $applicationId;
		}else{
			
			throw new Zend_Service_Exception("Application ID Required.");
		}
		
		if(!empty($sharedSecret)){
			
			$this->_sharedSecret  = $sharedSecret;
			
		}else{
			
			throw new Zend_Service_Exception("Shared Secret Required.");
		}	
		
		$this->accessToken       = $accessToken;
		$this->accessTokenSecret = $accessTokenSecret;
    
    }  
      
  
    /*****************************
     * CATALOG API 
     *****************************/  
      
    /**
     * Returns a collection of Zend_Service_Netflix_Title objects.
     * 
     * Options:
     * start_index, max_results
     * 
     * API CALL: /catalog/titles
     * 
     * @param String $term
     * @param array $options
     * @return array Zend_Service_Netflix_Title
     */  
    public function getTitles($term, array $options=array()){
    
    	//Validate term
		if(empty($term)){
			throw new Zend_Service_Exception("Auto Complete Term Can Not Be Empty.");	
		}
		
		//Method
		$method = "/catalog/titles";
		
		//Options
		$options['term']   = $term;
		$options['expand'] = "synopsis,
							  cast,
							  directors,
							  formats,
							  screen formats,
							  languages and audio,
							  similars,
							  awards,
							  bonus materials";
		$options           = $this->_buildOptions($options);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		
		//Check if there are errors
		if(!$response->isError()){
			
			//Initialize Title Container
			$titles = array();
			
			//Get the response
			$content = $response->getBody();
		
			//Parse XML and save titles into contains.
			$simpleXml = simplexml_load_string($content);
			
			//Instantiate Title Objects.
			require_once "Netflix/Title.php";
			foreach($simpleXml->catalog_title as $title){
			
				$Title = new Zend_Service_Netflix_Title();
				$Title->loadXML($title);
				
				array_push($titles, $Title);
				
			}
			
			return $titles;	
			
			
		}else{
			
			throw new Zend_Service_Exception($response->getMessage());
			
		}
    
    }  
      
      
    /**
     * Returns a specific Title as an object. 
     * 
     * type={movie|series|seasons|program|discs}
     * 
     * Options:
     * start_index, max_results
     * 
     * API CALL: 
     * catalog/titles/movies/titleid 
     * catalog/titles/series/seriesId
     * catalog/titles/programs/programId
     * catalog/titles/discs/discId
     * 
     * @param String $titleId Title id.
     * @param String $type
     * @param array $options
     * @return Object Zend_Service_Netflix_Title
     */  
    public function getTitle($titleId, $type='movie', array $options=array()){
    		
    	$types = array("movie", "series", "program", "disc");
    	
		//Validate id.
		if(empty($titleId)){
			throw new Zend_Service_Exception("Title Id Can Not Be Empty.");	
		}
		
		//Validate type.
		if(!in_array($type, $types)){
			throw new Zend_Service_Exception("Type is not valid.");
		}
		
		//Method.
		if($type == "movie"){
			$method = "catalog/titles/movies/".$titleId;
		}
		elseif($type == "series"){
			$method = "catalog/titles/series/".$titleId;
		}	
		elseif($type == "program"){
			$method = "catalog/titles/programs/".$titleId;
		}		
		elseif($type == "disc"){
			$method = "catalog/titles/discs/".$titleId;
		}
		
		//Options
		$options['expand'] = "synopsis,
							  cast,
							  directors,
							  formats,
							  screen formats,
							  languages and audio,
							  similars,
							  awards,
							  bonus materials";
		
		$options = $this->_buildOptions($options);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
	
		//Check if there are errors
		if(!$response->isError()){
			
			//Get the response
			$content = $response->getBody();
			
			//Create Catalog Object
			$simpleXml = simplexml_load_string($content);
			
			//Instantiate Title Objects.
			require_once "Netflix/Title.php";
			
			$Title = new Zend_Service_Netflix_Title();
			$Title->loadXML($simpleXml);

			return $Title;	
			
		}else{
			
			throw new Zend_Service_Exception($response->getMessage());
			
		}

    }  
  
  
    /**
     * Return a collection of possible String matches or submitted
     * search term. 
     * 
     * API CALL:
     * /catalog/titles/autocomplete
     * 
     * @param String $term Partial or Full title name.
     * @return Array Collection of Full Titles Found.
     */  
    public function getTitlesAutoComplete($term){
    	
    	//Validate term
		if(empty($term)){
			throw new Zend_Service_Exception("Auto Complete Term Can Not Be Empty.");	
		}
		
		//Initialize titles to return
		$titles = array();
		
		//Method
		$method = "catalog/titles/autocomplete";
		
		//Options
		$options['term'] = $term;
		$options         = $this->_buildOptions($options);

		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);

		//Check for errors
		if(!$response->isError()){
			
			//Get the content 
			$content = $response->getBody();
		
			//Create SimpleXML Object 
			$simpleXMLObj = simplexml_load_string($content);

			//Parse the results
			foreach($simpleXMLObj->autocomplete_item as $autocompleteItem){
				
				foreach($autocompleteItem as $title){
					array_push($titles, (string)$title['short']);
				}
			}
			
			return $titles;
			
		}else{
			
			throw new Zend_Service_Exception($response->getMessage());
			
		}	
    	
    }  
  
      
    /**
     * Returns a collection of Zend_Service_Netflix_Title objects simlilar to 
     * the title used as reference.
     * 
     * Options:
     * start_index, max_results
     * 
     * API CALL:
     * /catalog/titles/titleID/similars
     * 
     * @param String $titleId title id.
     * @param Array $options
     */  
    public function getSimilarTitles($titleId, array $options=array()){
    	
    	//Validate id
		if(empty($titleId)){
			throw new Zend_Service_Exception("Missing Title Id.");
		}
		
		//Method
		$method = "catalog/titles/title/".$titleId."/similars";
		
		//Options
		$options['expand'] = "synopsis,
							  cast,
							  directors,
							  formats,
							  screen formats,
							  languages and audio,
							  awards,
							  bonus materials";
		
		$options = $this->_buildOptions($options);
		
		//Call REST API.
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
	
	
		//If there are errors throw exception otherwise process.
		if(!$response->isError()){
			
		
			//Initialize Title Container
			$titles = array();
			
			//Get the response
			$content = $response->getBody();
		
			//Parse XML and save titles into contains.
			$simpleXml = simplexml_load_string($content);
			
			//Instantiate Title Objects.
			require_once "Netflix/Title.php";
			foreach($simpleXml->similars_item as $title){
			
				$Title = new Zend_Service_Netflix_Title();
				$Title->loadXML($title);
				
				array_push($titles, $Title);
				
			}
		
			return $titles;	
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}

    	
    }  
      
      
    /**
     * Returns a list of actors, directors, etc matching
     * the submited name as Zend_Service_Netflix_Person Objects.
     * 
     * Options:
     * start_index, max_results 
     * 
     * API CALL:
     * /catalog/people
     * 
     * @param String $name 
     * @param array $options
     */  
    public function getPeople($name, array $options=array()){
    	
    	//Validate name
		if(empty($name)){
			throw new Zend_Service_Exception("Missing Name parameter.");
		}
		
		//Method
		$method = "/catalog/people";
		
		//Options
		$options['term']   = $name;
		$options['expand'] = "filmography";
		$options 		   = $this->_buildOptions($options);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		if(!$response->isError()){
			
			//Initialize people container
			$people = array();
			
			//Get the content 
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$xml = simplexml_load_string($content);

			require_once "Netflix/Person.php";
			//Create a Person Object for each person found.
			foreach($xml->person as $person){
			
				$NetflixPerson = new Zend_Service_Netflix_Person();
				$NetflixPerson->loadXML($person);
				array_push($people, $NetflixPerson);
			}
			
			return $people;
			
		}else{
			
			throw new Zend_Service_Exception($response->getMessage());
			
		}
    	
    }  
      
  
    /**
     * Return a specific person as a Person Object.
     *
     * @param String $personId Id of Person.
     * @return Object Zend_Service_Netflix_Person
     */  
    public function getPerson($personId){
    	
    	//Validate name
		if(empty($personId)){
			throw new Zend_Service_Exception("Missing Person Id.");
		}
		
		//Method
		$method = "/catalog/people/".$personId;
		
		//Options
		$options['expand'] = "filmography";
		$options           = $this->_buildOptions($options);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		if(!$response->isError()){
			
			//Get the content 
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$xml = simplexml_load_string($content);

			require_once "Netflix/Person.php";
			$Person = new Zend_Service_Netflix_Person();
			$Person->loadXML($xml);
			
			return $Person;
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
    	
    	
    }  


	/*******************************
     * USER API CALLS
     *******************************/  

	/**
     * Return a specific user's information as a Zend_Service_Netflix_User 
     * object.
     * 
     * API CALL:
     * /users/userID
     *
     * @param String $userId User Id.
     * @return Object Zend_Service_Netflix_User
     */  
    public function getUser($userId){
    	
    	//Check if the user id is empty
		if(empty($userId)){
			throw new Zend_Service_Exception("Missing User ID.");
		}
		
		//Method
		$method = "users/".$userId;
		
		//Options
		$options = $this->_buildOptions(array(), true);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		//Check if there were any errors
		if(!$response->isError()){

			//Get the body of the response.
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$simpleXMLObj = simplexml_load_string($content);
			
			//Create Zend_Netflix_User Object
			require_once "Netflix/User.php";
			$User = new Zend_Service_Netflix_User();
			$User->loadXML($simpleXMLObj);
			
			return $User;
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
    		
    }  
  
	/**
     * Returns a collection of Zend_Service_Netflix_QueueItem objects.
     * 
     * $type = disc,instant 
     * $status = available,saved
     *
     * Options:
     * sort, start_index, max_results, updated_min
     * 
     * API CALL:
     * users/userID /queues
     * users/userID /queues/disc
     * users/userID /queues/disc/available
     * users/userID /queues/disc/saved
     * users/userID /queues/instant
     * users/userID /queues/instant/available
     * users/userID /queues/instant/saved
     * 
     * @param String $userId User Id
     * @param String $type
     * @param Array $options
     * @return Array Collection of Zend_Service_Netflix_QueueItem objects.
     */  
    public function getQueue($userId, $type='', $status = '', array $options=array()){
    	
    	//Initialize Containers 
 		$typeContainer   = array("disc", "instant");
    	$statusContainer = array("available", "saved"); 
 		
    	//Check if the user has supplied a userId
    	if(empty($userId)){
    		throw new Zend_Service_Exception("Missing User ID.");
    	}
    	
    	//Check if the user has supplied a valid type
    	if(empty($type) || !in_array($type, $typeContainer)){
    		throw new Zend_Service_Exception("Invalid Type.");
    	}
    
    	//Check if the user has supplied a valid status
    	if(empty($status) || !in_array($status, $statusContainer)){
    		throw new Zend_Service_Exception("Invalid Status.");
    	}
    
    	
    	//Check which call we want to make.
    	$method = "users/".$userId."/queues";
    	
    	if($type == "disc"){
    		
    		
    		$method = "/users/".$userId."/queues/disc";
    		
    		if($status == "available"){
    			
    			$method = "users/".$userId."/queues/disc/available";
    			
    		}elseif($status == "saved"){
    			
    			$method = "users/".$userId."/queues/disc/saved";
    			
    		}
	
    	}elseif($type == "instant"){
    		
    		$method = "users/".$userId."/queues/instant";
    		
    		if($status == "available"){
    			
    			$method = "users/".$userId."/queues/instant/available";
    			
    		}elseif($status == "saved"){
    			
    			$method = "users/".$userId."/queues/instant/saved";
    			
    		}
    		
    	}
    	
    	//Options
    	$options = $this->_buildOptions($options, true);
    	
   
    	//Create a Rest object and call API.
    	$restClient = $this->_getRestClient();
    	$response   = $restClient->restGet($method, $options);
    	 	
    	
    	//Check for errors
    	if(!$response->isError()){
    		
    		//Get the content
    		$content = $response->getBody();
    		
    		//Parse the data
    		$simpleXML = simplexml_load_string($content);
    		
    		//Initialize the queue item container.
    		$queueItems = array();
    		
    		//Foreach item create a QueueItem Object and add into container.
    		require_once "Netflix/QueueItem.php";
    		foreach($simpleXML->queue_item as $item){
    			
    			$QueueItem = new Zend_Service_Netflix_QueueItem();
    			$QueueItem->loadXML($item);
    			
    			array_push($queueItems, $QueueItem);
    		}
    		
    		
    		return $queueItems;
    		
    	}else{
    		
    		throw new Zend_Service_Exception($response->getMessage());
    		
    	}
    		
    	
    }  
  
     /**
     * Add/Update a Title to a Users queue.
     *
     * $type = disc, instant
     * 
     * Options:
     * format, position, etag
     * 
     * API CALL:
     * users/userID /queues/disc
     * users/userID /queues/instant
     *  
     * @param String $userId
     * @param String $titleURL
     * @param String $type
     * @param Array $options
     * @return String 
     */ 
    public function saveToQueue($userId, $titleURL, $type, array $options=array()){
    	

 		//Initialize Containers 
 		$typeContainer   = array("disc", "instant");
 		
    	//Check if the user has supplied a userId
    	if(empty($userId)){
    		throw new Zend_Service_Exception("Missing User ID.");
    	}
    	
    	//Check if the user has supplied a valid type
    	if(empty($type) || !in_array($type, $typeContainer)){
    		throw new Zend_Service_Exception("Invalid Type.");
    	}
    	
    	//Check if the user has entered a title to save to queue
    	if(empty($titleURL)){
    		throw new Zend_Service_Exception("Missing Title URL.");
    	}
    
    	
    	//Check which call we want to make.
    	if($type == "disc"){
    		
    		$method = "users/".$userId."/queues/disc";
    	
    	}elseif($type == "instant"){
    		
    		$method = "users/".$userId."/queues/instant";
    		
    	}
    	
    	
    	//Options
    	$options['title_ref'] = $titleURL;
    	$options 			  = $this->_buildOptions($options, true);
    	

    	//Create a Rest object and call API.
    	$restClient = $this->_getRestClient();   
    	$response   = $restClient->restPost($method, $options);
    	
    	//Check for errors
    	if(!$response->isError()){
    		
    		//Get the content
    		$content = $response->getBody();
    		
    		//Parse the data
    		$simpleXML = simplexml_load_string($content);
    		
    		//Check if the transaction was a success
    		if($simpleXML->message == "Move successful"){
    			return true;
    		}
    	
    		
    	}else{
    		
    		throw new Zend_Service_Exception($response->getMessage());
    		
    	}
    	
    }  
    
    /**
     * NOT FUNCTIONAL NOT FUNCTIONAL 
     * Delete a Title from a users queue.
     *
     * $type = disc, instant
     * $status = available, saved
     * 
     * API CALL:
     * users/userID /queues/disc/available/entryID
     * users/userID /queues/disc/saved/entryID
     * users/userID /queues/instant/available/entryID
     * users/userID /queues/instant/saved/entryID
     * 
     * @param String $userId
     * @param String $type
     * @param String $entyId
     */  
    public function deleteFromQueue($userId, $type, $status, $entryId){ 
    	
    	//Initialize Containers 
 		$typeContainer   = array("disc", "instant");
    	$statusContainer = array("available", "saved"); 
 		
    	//Check if the user has supplied a userId
    	if(empty($userId)){
    		throw new Zend_Service_Exception("Missing User ID.");
    	}
    	
    	//Check if the user has supplied a valid type
    	if(empty($type) || !in_array($type, $typeContainer)){
    		throw new Zend_Service_Exception("Invalid Type.");
    	}
    
    	//Check if the user has supplied a valid status
    	if(empty($status) || !in_array($status, $statusContainer)){
    		throw new Zend_Service_Exception("Invalid Status.");
    	}
    	
    	
    	//Check if the entryId is not empty.
    	if(empty($entryId)){
    		throw new Zend_Service_Exception("Missing Entry ID.");
    	}
    	
    	
    	//Check which call we want to make.
    	if($type == "disc"){
    		
    		if($status == "available"){
    			$method = "/users/T1u03JXn1Em7DhS5sxk3OiOtIBiC0o77JK041EH9AEiKs-/queues/disc/available/".$entryId;
    		}else{
    			$method = "users/".$userId."/queues/disc/saved/".$entryId;
    		}
    	
    	}else{
    		
    		if($status == "available"){
    			$method = "users/".$userId."/queues/instant/available/".$entryId;
    		}else{
    			$method = "users/".$userId."/queues/instant/saved/".$entryId;
    		}
    		
    	}
    	
    	
    	//Options
    	$options = $this->_buildOptions(array(), true);
    	
    	/*
    	$query = "";
    	foreach($options as $key => $value){
    		$query .= $key."=".$value."&";
    	}

    	$method = "users/T1u03JXn1Em7DhS5sxk3OiOtIBiC0o77JK041EH9AEiKs-/queues/disc/available";
    	
    	require_once "Zend/Http/Client.php";
    	$zend = new Zend_Http_Client(self::URI_BASE."/".$method."?".$query);
    	$return = $zend->request("GET");
    	echo $zend->getLastRequest();
    	
    	print_r($return);
    	*/
    	
    	
    	/*
    	echo $method;
    	//Create a Rest object and call API.
    	$restClient = $this->_getRestClient();    	
    	$response   = $restClient->restDelete($method, $query);
    	print_r($response);
    	exit();
    	
    	//Check for errors
    	if(!$response->isError()){
    		
    		//Get the content
    		echo $content = $response->getBody();
    		
    		//Parse the data
    		$simpleXML = simplexml_load_string($content);
    	
    		
    	}else{
    		
    		throw new Zend_Service_Exception($response->getMessage());
    		
    	}
    	*/
    	
    	
    }
    
     /**
     * Returns a list of Zend_Service_Netflix_AtHomeTitle objects.
     * Titles not yet returned to Netflix.
     *
     * Options:
     * start_index, max_results, updated_min
     * 
     * API CALL:
     * users/userID/at_home
     * 
     * @param String $userId
     * @param Array $options
     * @return Array Collection of Zend_Service_Netflix_AtHomeTitle objects.
     */  
    public function getTitlesAtHome($userId, array $options=array()){
    	
    	//Check userid is not null
		if(empty($userId)){
			throw new Exception("Missing UserId Parameter.");
		}
		
		//Check which api call we need to make.
		$method = "users/".$userId."/at_home";
		
		
		//Build Options
		$options = $this->_buildOptions($options, true);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		
		//Check if there were any errors
		if(!$response->isError()){

			//Get the body of the response.
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$simpleXML = simplexml_load_string($content);
			
			//Initialize the queue item container.
    		$atHomeItems = array();
    		
    		//Foreach item create a QueueItem Object and add into container.
    		require_once "Netflix/AtHomeItem.php";
    		foreach($simpleXML->at_home_item as $item){
    			
    			$AtHomeItem = new Zend_Netflix_Service_AtHomeItem();
    			$AtHomeItem->loadXML($item);
    			
    			array_push($atHomeItems, $AtHomeItem);
    		}
    		
    		return $atHomeItems;
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
    	
    }  
      
	/**
     * Returns a collection of Zend_Service_Netflix_Rating objects for a title or a series.
     * Netflix Predicted rating for the user is also included.
     *
     * API CALL:
     * users/userID /ratings/title
     * 
     * @param String $userId User Id
     * @param Array $titles
     * @return Array Collection of Zend_Service_Netflix_Rating objects. 
     */  
    public function getRatings($userId, array $titles){
    	
    	//Check userid is not null
		if(empty($userId)){
			throw new Exception("Missing UserId Parameter.");
		}
    	
    	//Set the title array into a string.
		$titles = implode(",", $titles);
		
		//Method.
		$method = "users/".$userId."/ratings/title";
		
		//Options
		$options['title_refs'] = $titles;
		$options 			   = $this->_buildOptions($options, true);
			
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		//Check if there were any errors
		if(!$response->isError()){

			//Get the body of the response.
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$simpleXML = simplexml_load_string($content);
			
			//Initialize the rating container.
    		$ratings = array();
    		
    		//Foreach rating returned create the object and place into container.
    		require_once "Netflix/Rating.php";
    		foreach($simpleXML->ratings_item as $item){
    			
    			$RatingItem = new Zend_Service_Netflix_Rating();
    			$RatingItem->loadXML($item);
    			
    			array_push($ratings, $RatingItem);
    		}
    		
    		return $ratings;
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
		
    }  
    
    /**
     * Add a rating to a title for the user.
     *
     * API CALL:
     * users/userID /ratings/title/actual
     * 
     * @param String $userId
     * @param String $title
     * @param String $rating 1-5 OR 'not_interested' OR 'no_opinion'
     * @return boolean
     */  
    public function addRating($userId, $titleURL, $rating){
    	
    	//Valid Ratings
    	$validRatings = array('1', '2', '3', '4', '5', 'not_interested', 'no_opinion');
    	
    	//Check if the userId is not null
    	if(empty($userId)){
			throw new Exception("Missing UserId Parameter.");
		}
		
		//Check if the title is not null
		if(empty($titleURL)){
			throw new Exception("Missing Title URL Parameter.");
		}
		
		//Check if the rating is 1 and 5 or 'not_interested' OR 'no_opinion'
    	if(empty($rating) || !in_array($rating, $validRatings)){
    		throw new Zend_Service_Exception("Invalid Rating.");
    	}
			   
		
		//Method.
		$method = "users/".$userId."/ratings/title/actual";
		
		//Options
		$options['title_ref'] = $titleURL;
		$options['rating'] 	  = $rating;	 
		$options 			  = $this->_buildOptions($options, true);
			

		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restPost($method, $options);
		

		//Check if there were any errors
		if(!$response->isError()){

			//Get the body of the response.
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$simpleXML = simplexml_load_string($content);
			
			//Check if it was successfull
			if((string)$simpleXML->message == "Success, Your rating has been set"){
				return true;
			}else{
				return false;
			}
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
    	
    }  
    
  
	/**
     * Update a user's rating on a title.
     *
     * API CALL:
     * users/userID /ratings/title/actual/ratingID
     * 
     * @param String $userId
     * @param String $ratingId
     * @param String $rating 1-5 OR 'not_interested' OR 'no_opinion'
     * @return boolean
     */  
    public function updateRating($userId, $ratingId, $rating){ 
  	
    	//Valid Ratings
    	$validRatings = array('1', '2', '3', '4', '5', 'not_interested', 'no_opinion');
    	
    	//Check if the userId is not null
    	if(empty($userId)){
			throw new Exception("Missing UserId Parameter.");
		}
		
		//Check if the title is not null
		if(empty($ratingId)){
			throw new Exception("Missing Rating ID Parameter.");
		}
		
		//Check if the rating is 1 and 5 or 'not_interested' OR 'no_opinion'
    	if(empty($rating) || !in_array($rating, $validRatings)){
    		throw new Zend_Service_Exception("Invalid Rating.");
    	}
			   
		
		//Method.
		$method = "users/".$userId."/ratings/title/actual/".$ratingId;
		
		//Options
		$options['rating'] 	  = $rating;	 
		$options 			  = $this->_buildOptions($options, true);
			
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restPut($method, $options);
		
		
		//Check if there were any errors
		if(!$response->isError()){

			//Get the body of the response.
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$simpleXML = simplexml_load_string($content);
			
			//Check if it was successfull
			if((string)$simpleXML->message == "Success, Your rating has been set"){
				return true;
			}else{
				return false;
			}
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
		
    	
    } 
        
    
    /**
     * Returns the Netflix predicted rating(s) for a title or titles.
     *
     * API CALL:
     * users/userID /reviews
     * 
     * 
     * @param String $userId
     * @param Array $titles
     * @return Array Collection of Zend_Service_Netflix_Rating objects.s
     */  
    public function getPredictRating($userId, array $titles){  
  
    	//Check userid is not null
		if(empty($userId)){
			throw new Exception("Missing User ID Parameter.");
		}
    	
		//Format the titles array
		$titles = implode(",", $titles);
			
		//API.
		$method = "users/".$userId."/ratings/title/predicted";
		
		//Options
		$options['title_refs'] = $titles;
		$options = $this->_buildOptions($options, true);
					
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		
		//Check if there were any errors
		if(!$response->isError()){

			//Initialize container
			$predictedRatingItemContainer = array();
			
			//Get the body of the response.
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$simpleXMLObj = simplexml_load_string($content);
			
			//Foreach predicted rating create an object.
			require_once "Netflix/Rating.php";
			foreach($simpleXMLObj->ratings_item as $ratingItem){
				
				$PredRatingItem = new Zend_Service_Netflix_Rating();
				$PredRatingItem->loadXML($ratingItem);
				
				array_push($predictedRatingItemContainer, $PredRatingItem);
				
			}
			
			return $predictedRatingItemContainer;
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
		
	}
    
    
    /**
     * Returns a collection of Zend_Service_Netflix_Rating objects.
     * Recommendations are based off the users ratings and rental history.
     *
     * Options:
     * start_index, max_results
     * 
     * API CALL
     * users/userID/recommendations
     * 
     * @param String $userId User Id
     * @param Array $options
     * @return Array Collection of Zend_Service_Netflix_Rating objects.
     */  
    public function getRecommendations($userId, array $options=array()){  
      	
		//Check if the user id is not empty
		if(empty($userId)){
			throw new Exception("Missing UserID Parameter.");
		}
		
		//Method
		$method = "/users/".$userId."/recommendations";
		
		//Options
		$options = $this->_buildOptions($options, true);
		
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		//Check if there were any errors
		if(!$response->isError()){

			//Initialize item container.
			$recommendationContainer = array();
			
			//Get the body of the response.
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$simpleXMLObj = simplexml_load_string($content);
			
			//Create Recommendation Object foreach item found
			foreach($simpleXMLObj->recommendation as $item){
				
				require_once "Netflix/RecommendationItem.php";
				$Item = new Zend_Service_Netflix_Recommendation();
				$Item->loadXML($item);
				
				array_push($recommendationContainer, $Item);
				
			}
			
			return $recommendationContainer;
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
		
		
	}
    
    
	/**
     * Returns a user's reviews as a collection of Zend_Service_Netflix_Review Objects.
     * Or returns a user's review of a title/titles.
     *
     * Options Params
     * start_index, max_results, updated_min
     * 
     * API CALL:
     * users/userID /reviews
     * 
     * @param String $userId
     * @param Array $titles
     * @return Array Collection of Zend_Service_Netflix_Review objects.
     */  
    public function getReviews($userId, array $titles, array $options=array()){  
      
    	//Check userid is not null
		if(empty($userId)){
			throw new Exception("Missing User ID Parameter.");
		}
    	
		//Seperate the titles by commas
		$titles = implode(",", $titles);
		
		
		//Method.
		$method = "users/".$userId."/reviews";
		
		//If we do not set the param title_refs we display all of the reviews.
		if(!empty($title)){
			$options['title_refs'] = $titles;
		}
		
		$options = $this->_buildOptions($options, true);
				
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		//Check if there were any errors
		if(!$response->isError()){

			//Initialize the container
			$reviewsContainer = array();
			
			//Get the body of the response.
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$simpleXMLObj = simplexml_load_string($content);
			
			//Create object for the review.
			require_once "Netflix/Review.php";
			foreach($simpleXMLObj->review as $review){
				
				$Review = new Zend_Service_Netflix_Review();
				$Review->loadXML($review);
				
				array_push($reviewsContainer, $Review);
			}
			
		
			return $reviewsContainer;
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}

	}
	
	
    /**
     * Return a collection of RentalHistoryItem objects.
     * 
     * History Type:
     * all, shipped, returned, watched
     * 
     * Options:
     * start_index, max_results, updated_min
     * 
     * API CALL:
     * users/userID /rental_history
     * users/userID /rental_history/shipped
     * users/userID /rental_history/returned
     * users/userID /rental_history/watched
     * 
     * @param String $userId
     * @param String $historyType
     * @param Array $options
     * @return Array Colletion of Zend_Service_Netflix_RentalHistoryItem object.
     */  
    public function getRentalHistory($userId, $historyType='', array $options=array()){
    	
    	//Check userid is not null
		if(empty($userId)){
			throw new Exception("Missing User ID Parameter.");
		}
		
		//Method - Default API.
		$method = "users/".$userId."/rental_history";
		
		if($historyType == "shipped"){
			$method = "users/".$userId."/shipped";
		}elseif($historyType == "returned"){
			$method = "users/".$userId."/returned";
		}elseif($historyType == "watched"){
			$method = "users/".$userId."/watched";
		}
		
		$options = $this->_buildOptions($options, true);
				
		//Call REST API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		
		//Check if there were any errors
		if(!$response->isError()){

			//Initialize the container
			$itemsContainer = array();
			
			//Get the body of the response.
			$content = $response->getBody();
			
			//Create SimpleXML Object 
			$simpleXMLObj = simplexml_load_string($content);
			
			//Create object for the rental history.
			require_once "Netflix/RentalHistoryItem.php";
			foreach($simpleXMLObj->rental_history_item as $historyItem){
				
				$RentalHistoryItem = new Zend_Service_Netflix_RentalHistoryItem();
				$RentalHistoryItem->loadXML($historyItem);
				
				array_push($itemsContainer, $RentalHistoryItem);
			}
			
		
			return $itemsContainer;
			
		}else{
			throw new Zend_Service_Exception($response->getMessage());
		}
    	
    }  
      
	
    /**
     * Creates an instance of a rest client to use
     *
     * @return Zend_Rest_Client
     */  
    protected function _getRestClient(){
    	
    	if($this->_restClient === null){
		
			require_once "Zend/Rest/Client.php";
			$this->_restClient = new Zend_Rest_Client(self::URI_BASE);
				
		}
		
		return $this->_restClient;
		
    }  
      
      
    /**
     * Creates a randomly generated value used in the 
     * oauth_nonce parameter.
     *
     * @return String
     */  
    protected function _getOAuthNOnce(){
    	
    	return time();
    	
    }  
      
         
    /**
     * Creates time stamp.  Used as
     * oauth_timestamp parameter value.
     *
     * @return String
     */  
    protected function _getOAuthTimeStamp(){
    	
    	return time();
    	
    }  
      
      
    /**
     * Generate the Oauth Default Options that is required for all 
     * Netflix API calls.
     *
     * @return Array
     */  
    protected function _getOauthDefaultOptions($enableAccessToken=false){
    	
    	$defaultOptions = array("oauth_consumer_key"     	=> $this->_consumerKey,
							    "oauth_nonce"			  	=> self::_getOAuthNOnce(),
							    "oauth_signature"			=> urlencode($this->_sharedSecret."&"),
							    "oauth_signature_method" 	=> self::SIGNITURE_METHOD,
					   		    "oauth_timestamp"        	=> self::_getOAuthTimeStamp(),
					   		    "oauth_version" 			=> self::VERSION
					   		   );

		//If AccessToken Options are enabled add more options
		if($enableAccessToken){
			$defaultOptions['oauth_token']	    = $this->accessToken;
			$defaultOptions['oauth_signature']	= urlencode($this->_sharedSecret."&".$this->accessTokenSecret);   		    
		}
					   		     
		return $defaultOptions;			
    	
				
    }  
      
      
      
    /**
     * Buld options to send to the API call. Merges user entered
     * query options with the default required options returned by
     * _getOauthDefaultOptions
     *
     * @param array $options
     * @return Boolean $enableAccessToken Set to true is were access user restricted data.
     */  
    protected function _buildOptions(array $options=array(), $enableAccessToken=false){
    	
		return array_merge($options, $this->_getOauthDefaultOptions($enableAccessToken));
	
    }  
      
     
    /**
     * Creates URL for the application to direct the user
     * to grant access to the Application.
     * 
     * Response generates user_id, access_token, and acess_token_secret
     * This data is unique to each user and must be stored locally if 
     * application needs to use it at a future date.
     * 
     * 
     * @param String $callbackURL URL to send the user to after granting access to your app.
     * @return String Formated URL
     */  
    public function getRequestTokenAuthorizationURL($callbackURL){
    	
    	//Generate the Request Token data.
		$this->_getRequestTokenData();
		
		//Append requestToken and requestSecretKey.
		$appendQuery = "?request_token=".$this->_requestToken.
					   "&request_token_secret=".$this->_requestTokenSecret;
					   
		$callbackURL = $callbackURL.$appendQuery;
		
		//Method call.
		$method = "/oauth/login";
		
		//Build complete Query,
		$query = "?application_name=".$this->_applicationName.
				 "&oauth_token=".$this->_requestToken.
				 "&oauth_consumer_key=".$this->_consumerKey.
				 "&oauth_callback=".urlencode($callbackURL);
		
		$url    = self::API_USER_URI_BASE.$method.$query;
		
		return $url;
    	
    }  
    
    
      
    /**
     * Get the request token information from Netflix.
     */  
    protected function _getRequestTokenData(){
    	
		//Method to call.
		$method = "/oauth/request_token";
		
		//Options.
		$options  = $this->_getOauthDefaultOptions();
		
		//Call the API
		$restClient = $this->_getRestClient();
		$response = $restClient->restGet($method, $options);
	
		if(!$response->isError()){
			
			//Get the body to parse the token info.
			$content = $response->getBody();
			$params  = explode("&", $content);
			
			foreach($params as $param){
				
				$values = explode("=", $param);
				
				if($values[0] == "oauth_token_secret"){
					$this->_requestTokenSecret = $values[1];
				}
				
				if($values[0] == "oauth_token"){
					$this->_requestToken = $values[1];
				}
				
				if($values[0] == "application_name"){
					$this->_applicationName = $values[1];
				}
				
			}	
		
		}else{
			throw new Exception($response->getMessage());
		}
    	
    	
    }  
    

    /**
     * Generate Access Token Data.
     *
     * @param String $requestedToken
     * @param String $requestedTokenSecret
     * @return Array $accessTokenData Collection of accesstoken info for the user.
     */  
    public function getAccessTokenData($requestedToken, $requestedTokenSecret){
    	
    	//Method to call.
    	$method = "oauth/access_token";
		
    	//Build Options for call.
    	$options 					= $this->_buildOptions(array());
    	$options['oauth_signature']	= urlencode($this->_sharedSecret."&".$requestedTokenSecret);
    	$options['oauth_token']	    = $requestedToken;
    	
    	//Call API
		$restClient = $this->_getRestClient();
		$response   = $restClient->restGet($method, $options);
		 
		
		if(!$response->isError()){
			
			$content = $response->getBody();
			
			//Parse out the access token information
			$params  = explode("&", $content);
			
			//Initializa contains for the accesstoken data.
			$accessDataContainer = array();
			
			foreach($params as $param){
				
				$values = explode("=", $param);
				
				if($values[0] == "user_id"){
					$accessDataContainer['userId'] = $values[1];
				}
				
				if($values[0] == "oauth_token"){
					$accessDataContainer['oauthToken']  = $values[1];
				}
				
				if($values[0] == "oauth_token_secret"){
					$accessDataContainer['oauthTokenSecret'] = $values[1];
				}
				
			}	
			
			return $accessDataContainer; 
			
		}else{
			throw new Exception($response->getMessage());
		}

    	
    }  
  
}